#region Copyright and Licensing Notice
// Copyright (C) 2011 Steven Bosnick
// 
// This program is open source software; you can redistribute it 
// and/or modifiy it under the terms of the Eclipse Public License,
// version 1.0.
// 
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A 
// PARTICULAR PURPOSE. See the Eclipse Public License for more
// details.
// 
// You should have received a copy of the Eclipse Public License 
// along with this program; if not, you can find a copy at
// "http://www.opensource.org/licenses/eclipse-1.0.php".
#endregion
using System;
using BitwiseOre.SharedMemory.Core;
using BitwiseOre.SharedMemory.Core.Primatives;
using NUnit.Framework;
using Moq;

namespace BitwiseOre.Tests.SharedMemory.Primatives
{
    [TestFixture]
    public sealed class SharedByteArrayFixture : AssertionHelper
    {
        [Test(Description = "Checks that reading an array of bytes delgates to reading an array from the accessor")]
        public void ReadArraySegment_DelegatesToAccessor()
        {
            const int offset = 5;
            var accessor = new Mock<IUnmanagedMemoryAccessor>();
            var dest = new ArraySegment<byte>(new byte[10], 2, 5);

            var array = new SharedByteArray(accessor.Object);
            array.ReadArraySegment(offset, dest);

            accessor.Verify(a => a.ReadArray(offset, dest.Array, dest.Offset, dest.Count),
                            "Read array from the accessor with unexpected parameters or no read array.");
        }

        [Test(Description = "Checks that reading an array of bytes returns the result of delegating to " +
                            "the accessor")]
        public void ReadArraySegment_ReturnsResultFromAccessor()
        {
            const int expectedresult = 5;
            var accessor = new Mock<IUnmanagedMemoryAccessor>();
            accessor.Setup(a => a.ReadArray(It.IsAny<long>(), It.IsAny<byte[]>(),
                                            It.IsAny<int>(), It.IsAny<int>()))
                .Returns(expectedresult);

            var array = new SharedByteArray(accessor.Object);
            var result = array.ReadArraySegment(5, new ArraySegment<byte>(new byte[10], 2, 5));

            Expect(result, EqualTo(expectedresult),
                   "Unexpected return value when reading an array segment.");
        }

        [Test(Description = "Checks that writing an array of bytes delgates to writing the array to the accessor")]
        public void WriteArraySegment_DelegatesToAccessor()
        {
            const int offset = 5;
            var accessor = new Mock<IUnmanagedMemoryAccessor>();
            var source = new ArraySegment<byte>(new byte[10], 2, 5);

            var array = new SharedByteArray(accessor.Object);
            array.WriteArraySegment(offset, source);

            accessor.Verify(a => a.WriteArray(It.Is<long>(p => p == offset),
                                              It.Is<byte[]>(p => p == source.Array),
                                              It.Is<int>(o => o == source.Offset),
                                              It.IsAny<int>()),
                            "WriteArraySegment() did not delegate to WriteArray() as expected.");
        }

        [Test(Description = "Checks that writting an array of bytes writes all of them if there is " +
                            "suffienct room in the accessor")]
        public void WriteArraySegment_WritesAllBytesIfSufficientCapacity()
        {
            const int offset = 5;
            const int capacity = 8;
            const int count = 2;
            var accessor = new Mock<IUnmanagedMemoryAccessor>();
            accessor.SetupGet(a => a.Capacity).Returns(capacity);
            var source = new ArraySegment<byte>(new byte[10], 2, count);

            var array = new SharedByteArray(accessor.Object);
            array.WriteArraySegment(offset, source);

            accessor.Verify(a => a.WriteArray(It.IsAny<long>(),
                                              It.IsAny<byte[]>(),
                                              It.IsAny<int>(),
                                              It.Is<int>(i => i == count)),
                            "Writing the array segment did not write all of the bytes.");
        }

        [Test(Description = "Checks that writting an array of bytes writes a reduced number of bytes " +
                            "if there isn't room for all of them in the accessor.")]
        public void WriteArraySegment_WithInsufficientCapacity()
        {
            const int offset = 5;
            const int capacity = 8;
            const int count = 4;
            var accessor = new Mock<IUnmanagedMemoryAccessor>();
            accessor.SetupGet(a => a.Capacity).Returns(capacity);
            var source = new ArraySegment<byte>(new byte[10], 2, count);

            var array = new SharedByteArray(accessor.Object);
            array.WriteArraySegment(offset, source);

            accessor.Verify(a => a.WriteArray(It.IsAny<long>(),
                                              It.IsAny<byte[]>(),
                                              It.IsAny<int>(),
                                              It.Is<int>(i => i == capacity - offset)),
                            "Writing the array segment did not write the correct number of the bytes.");
            
        }

        [Test(Description = "Checks that writting an array of bytes returns the number of bytes written")]
        public void WriteArraySegment_ReturnsNumberOfBytesWritten()
        {
            const int offset = 5;
            const int capacity = 8;
            const int count = 4;
            var accessor = new Mock<IUnmanagedMemoryAccessor>();
            accessor.SetupGet(a => a.Capacity).Returns(capacity);
            var source = new ArraySegment<byte>(new byte[10], 2, count);

            var array = new SharedByteArray(accessor.Object);
            var result = array.WriteArraySegment(offset, source);
            
            Expect(result, EqualTo(capacity -offset),
                   "Unexpected result returned when writing an array of bytes.");
        }

    }

}